package com.xialing.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.ThreadPoolExecutor;

/**
 * @Author: xialing
 * @Description
 */
@Configuration
@EnableAsync
public class ThreadPoolTaskConfig {

    @Bean("threadPoolTaskExecutor")
    public ThreadPoolTaskExecutor threadPoolTaskExecutor() {
        ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();

        //线程池创建的核心线程数，线程池维护线程的最小数量，默认情况下会一直存活，直到当前线程数量达到核心线程数，才会回收多余的线程
        //如果设置了allowCoreThreadTimeout=ture（默认是false）时，核心线程会超时关闭
        threadPoolTaskExecutor.setCorePoolSize(16);

        //线程池的阻塞队列，当核心线程数达到最大时，其他任务会放到阻塞队列中，等待执行
        threadPoolTaskExecutor.setQueueCapacity(1024);

        //线程池的最大线程数，当核心线程数达到最大，并且阻塞队列也满了，会启动新线程处理任务
        //如果设置allowCoreThreadTimeout=ture时，则最大线程数无效
        //如果最大线程数也满了，则线程池会拒绝处理任务并抛出异常
        threadPoolTaskExecutor.setMaxPoolSize(64);

        //当线程空闲时间达到keepAliveTime时，线程会退出，直到线程数量等于corePoolSize，如果allowCoreThreadTimeout=true，则会终止
        //允许线程空闲时间30秒，当maxPoolSize的线程在空闲时间达到的时候销毁
        //如果allowCoreThreadTimeout=ture，则keepAliveTime无效，则会知道线程数量为0
        threadPoolTaskExecutor.setKeepAliveSeconds(30);

        //spring 提供的 ThreadPoolTaskExecutor 线程池，是有setThreadNamePrefix() 方法的。
        //jdk 提供的ThreadPoolExecutor 线程池是没有 setThreadNamePrefix() 方法的
        threadPoolTaskExecutor.setThreadNamePrefix("threadPoolTaskExecutor-");

        //rejection-policy：当pool已经达到max size的时候，如何处理新任务
        //ThreadPoolExecutor.AbortPolicy()：丢弃任务并抛出RejectedExecutionException异常。
        //ThreadPoolExecutor.DiscardPolicy()：也是丢弃任务，但是不抛出异常。
        //ThreadPoolExecutor.DiscardOldestPolicy()：丢弃队列最前面的任务，然后重新尝试执行任务（重复此过程）
        //ThreadPoolExecutor.CallerRunsPolicy()：由调用线程（提交任务的线程）处理该任务
        threadPoolTaskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());

        threadPoolTaskExecutor.initialize();

        return threadPoolTaskExecutor;
    }

}
